import { defineAsyncComponent, reactive, ref, Ref, UnwrapNestedRefs } from "vue";

export class ModalOptions {
    Type: string;
    Prefix: string;
    Title: string;
    Content: string;
    ContentType: string;
    Buttons: Array<string>;
    Task: ((value: string | PromiseLike<string>) => void) | undefined = undefined;

    constructor(type: string, prefix: string = '/src/components/Modal/', title: string = '提示', content: string = '', contentType: string = '', buttons: Array<string> = []) {
        this.Type = type;
        this.Prefix = prefix;
        this.Title = title;
        this.Content = content;
        this.ContentType = contentType;
        this.Buttons = buttons;
    }

    public static Copy(source: ModalOptions, destination: ModalOptions): void {
        destination.Type = source.Type;
        destination.Prefix = source.Prefix;

        destination.Title = source.Title;
        destination.Content = source.Content;
        destination.ContentType = source.ContentType;

        destination.Buttons.clear();
        destination.Buttons.addRange(source.Buttons);
    }

    public static Default(): ModalOptions {
        return new ModalOptions('');
    }

    public WithType(this: ModalOptions, type: string): ModalOptions {
        this.Type = type;
        return this;
    }

    public WithPrefix(this: ModalOptions, prefix: string): ModalOptions {
        this.Prefix = prefix;
        return this;
    }

    public WithTitle(this: ModalOptions, title: string): ModalOptions {
        this.Title = title;
        return this;
    }

    public WithContent(this: ModalOptions, content: string): ModalOptions {
        this.Content = content;
        return this;
    }

    public WithContentType(this: ModalOptions, contentType: string): ModalOptions {
        this.ContentType = contentType;
        return this;
    }

    public WithButtons(this: ModalOptions, buttons: Array<string>): ModalOptions {
        this.Buttons.clear();
        this.Buttons.addRange(buttons);
        return this;
    }
}

/**
 * 模态组件
 */
export default class ModalComponent {
    private static instance: ModalComponent = new ModalComponent();
    /**
     * 模态组件
     */
    public static get Default(): ModalComponent {
        return this.instance;
    }

    constructor() {
        window.addEventListener('unload', this.Dispose.bind(this));

        for (const [key, module] of Object.entries(import.meta.glob('/src/components/Modal/*.vue'))) {
            this.modules[key] = module as () => Promise<{ [key: string]: any; }>;
        }
    }

    Dispose() {
        window.removeEventListener('unload', this.Dispose);

        this.State.value = false;
        this.url = '';
    }

    public State: Ref<boolean> = ref(false);
    public url: string = '';
    private modules: Record<string, () => Promise<{ [key: string]: any; }>> = reactive({});

    public Options: UnwrapNestedRefs<ModalOptions> = reactive(new ModalOptions(''));

    public DynamicComponent() {
        return defineAsyncComponent(this.modules[this.url]);
    }

    public AddDynamicModules(modules: Record<string, () => Promise<unknown>>): void {
        for (const [key, module] of Object.entries(modules)) {
            this.modules[key] = module as () => Promise<{ [key: string]: any; }>;
        }
    }

    public PopupAsync(options: ModalOptions): Promise<string> {
        this.State.value = true;

        ModalOptions.Copy(options, this.Options);
        this.Options.Title = this.Options.Title ?? '提示';
        this.Options.Prefix = this.Options.Prefix ?? '/src/components/Modal/';

        this.url = this.Options.Prefix.concat(`${this.Options.Type}`, '.vue');
        return new Promise(resolve => this.Options.Task = resolve);
    }

    public TrySetResult(result: string | PromiseLike<string>): void {
        if (this.Options.Task != undefined) {
            this.Options.Task(result);
            this.Options.Task = undefined;

            this.State.value = false;
            this.url = '';
        }
    }
}